package com.wuyb.socket;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.wuyb.mapper.MeetingUserMapper;
import com.wuyb.pojo.MeetingUser;
import com.wuyb.pojo.User;
import com.wuyb.util.RedisUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

/**
 * Socket事件监听器
 *
 * @Author: wyb
 * @Date: 2024/01/07/17:39
 * @Description:
 */
@Component
@Slf4j
public class SocketHandler {

    @Resource
    private SocketSender socketSender;

    @Resource
    private MeetingUserMapper meetingUserMapper;

    @Resource
    private SocketIOServer socketIOServer;

    @Resource
    private SocketMapDao socketMapDao;

    @Resource
    private RedisUtil redisUtil;

    /**
     * 连接上的用户公共房间
     */
    private final static String CONNECTROOMID = "CONNECTED";


    /**
     * 监听连接
     *
     * @param client
     */
    @OnConnect
    public void onConnectEvent(SocketIOClient client) {
        log.info(String.format("连接成功 %s", client.getSessionId()));
    }


    /**
     * 断开连接
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnectEvent(SocketIOClient client) {
        SocketUser socketUser = socketMapDao.getSocketUserByUUID(client.getSessionId());
        if (socketUser == null) {
            return;
        }

        // 更新每个会议的人数
        User users = socketUser.users;

        // 连接的用户断开麦克风，断开投屏
        socketUser.meetings.forEach(
                mid -> meetingUserMapper.update(
                        new MeetingUser().setSpeeching(false).setUping(false),
                        new QueryWrapper<MeetingUser>()
                                .eq("meeting_id_xq", mid)
                                .eq("users_id_xq", users.getId())
                )
        );
        // 对进入的每个房间，告诉其他人，这个人走了
        socketUser.meetings.forEach(
                mid -> socketSender.sendMeetWithout(client, mid, "left_user", users.getId())
        );
        // 连接信息删除
        socketMapDao.deleteSocketUserByUUID(client.getSessionId());
        log.info(String.format("断开连接：%s", client.getSessionId()).concat(" ").concat(String.valueOf(socketMapDao.getSize())));
    }


    /**
     * 接收连接人的信息
     *
     * @param client
     * @param user
     */
    @OnEvent("info")
    public void onInfoEvent(SocketIOClient client, User user) {

        // 加入连接的用户列表
        SocketUser socketUser = new SocketUser(client, user, new ArrayList<>());
        socketMapDao.putSocketUser(client.getSessionId(), user.getId(), socketUser);

        // 加入用户公共房间
        client.joinRoom(CONNECTROOMID);
        log.info(String.format("info:%s", user));
    }


    /**
     * 房间消息
     *
     * @param client
     * @param jsonObject
     */
    @OnEvent("meetchat")
    public void onMeetChatEvent(SocketIOClient client, JSONObject jsonObject) {
        String meetingId = jsonObject.getString("meetingId");
        User users = socketMapDao.getSocketUserByUUID(client.getSessionId()).users;
        socketSender.sendMeetChat(meetingId, users, jsonObject);
        log.info(String.format("meetchat: %s", users));
    }


    /**
     * 请求加入会议
     *
     * @param client
     * @param jsonObject
     */
    @OnEvent("join")
    public void onJoinRoomEvent(SocketIOClient client, JSONObject jsonObject) {
        String meetingId = jsonObject.getString("meetingId");
        // 如果存在
        if (socketSender.isExist(meetingId, client)) {
            socketSender.sendUserListById(meetingId, socketSender.getUserIdBySession(client.getSessionId()));
            return;
        }

        // 新加入了用户信息
        SocketUser socketUser = socketMapDao.getSocketUserByUUID(client.getSessionId());
        User users = socketUser.users;
        // 告诉客户端已经可以进行sdp交换了
        JSONObject res = new JSONObject();
        res.put("type", "joined");
        res.put("meetingId", meetingId);
        client.sendEvent("message", res);

        // 向房间里的人发送加入消息
        socketIOServer.getRoomOperations(meetingId).sendEvent("joined_user", users);
        socketSender.sendMeetChatBySys(meetingId, users.getName().concat("加入房间"));

        // 记录这个逼加入房间
        socketUser.getMeetings().add(meetingId);
        socketMapDao.putSocketUser(socketUser.getClient().getSessionId(), socketUser.getUsers().getId(), socketUser);

        client.joinRoom(meetingId);
        socketSender.sendUserListById(meetingId, users.getId());
        log.info(String.format("%s 加入房间 %d", users.getName(), socketIOServer.getRoomOperations(meetingId).getClients().size()));
    }


    /**
     * WebRTC建立通话
     *
     * @param client
     * @param data
     */
    @OnEvent("message")
    public void onMessageEvent(SocketIOClient client, JSONObject data) {
        String meetingId = data.getString("meetingId");
        Integer toId = data.getInteger("toId");
        if (toId != null) {
            socketSender.sendMeetById(toId, meetingId, "message", data);
        } else {
            socketSender.sendMeetWithout(client, meetingId, "message", data);
        }
        log.info(String.format("Message: %s", data));
    }


    /**
     * 离开房间
     *
     * @param client
     * @param data
     */
    @OnEvent("leave")
    public void onLeaveEvent(SocketIOClient client, JSONObject data) {
        String meetingId = data.getString("meetingId");
        client.leaveRoom(meetingId);
        socketSender.sendMeetWithout(client, meetingId, "left_user", socketSender.getUserIdBySession(client.getSessionId()));
        String name = socketMapDao.getSocketUserByUUID(client.getSessionId()).users.getName();
        log.info(String.format("%s 离开房间 %d", name, socketIOServer.getRoomOperations(meetingId).getClients().size()));
    }


    /**
     * 会议存在心跳，每发送一次，存在事件就加上1分钟
     *
     * @param client
     * @param data
     */
    @OnEvent("exist_minute")
    private void onExistMinuteEvent(SocketIOClient client, JSONObject data) {
        log.info(String.format("exist_minute: %s", data));
        String meetingId = data.getString("meetingId");
        Integer userId = socketSender.getUserIdBySession(client.getSessionId());
        MeetingUser meetingUser = meetingUserMapper.selectOne(
                new QueryWrapper<MeetingUser>()
                        .eq("meeting_id_xq", meetingId)
                        .eq("users_id_xq", userId)
        );
        if (meetingUser == null) {
            return;
        }
        Integer existMinute = meetingUser.getExistMinute();
        meetingUserMapper.update(
                meetingUser.setExistMinute(existMinute + 1),
                new QueryWrapper<MeetingUser>()
                        .eq("meeting_id_xq", meetingId)
                        .eq("users_id_xq", userId)
        );

    }
}
